package pkev.xgrapher.component;

import pkev.xgrapher.common.GrapherFactory;
import pkev.xgrapher.component.models.AbstractGrapherModel;
import pkev.xgrapher.component.models.Axis;
import pkev.xgrapher.component.models.Caption;
import pkev.xgrapher.component.models.Grid;
import pkev.xgrapher.transformation.AbstractTransformation;

import java.awt.*;
import java.util.*;
import java.util.List;

public class XGrapherController {
    private ArrayList<AbstractGrapherModel> featureDrawModels = null;
    private GrapherFactory grapherFactory = null;
    private ArrayList<Class> registerModels = null;

    public XGrapherController() {
        getRegisterModels().add(Axis.class);
        getRegisterModels().add(Caption.class);
        getRegisterModels().add(Grid.class);
    }

    protected ArrayList<AbstractGrapherModel> getFeatureDrawModels() {
        if (featureDrawModels == null) {
            featureDrawModels = new ArrayList<AbstractGrapherModel>();
        }
        return featureDrawModels;
    }

    public ArrayList<Class> getRegisterModels() {
        if (registerModels == null) {
            registerModels = new ArrayList<Class>();
        }
        return registerModels;
    }

    public void setRegisterModels(ArrayList<Class> registerModels) {
        this.registerModels = registerModels;
    }

    protected void setFeatureDrawModels(ArrayList<AbstractGrapherModel> featureDrawModels) {
        this.featureDrawModels = featureDrawModels;
    }

    public void clearFeatureDrawModels() {
        featureDrawModels.clear();
    }

    public GrapherFactory getGrapherFactory() {
        return grapherFactory;
    }

    public void setGrapherFactory(GrapherFactory grapherFactory) {
        this.grapherFactory = grapherFactory;
    }

    public void addFeatureDrawModels(AbstractGrapherModel ... models) {
        for (AbstractGrapherModel model : models) {
            if (!getFeatureDrawModels().contains(model)){
                getFeatureDrawModels().add(model);
            }
        }
    }

    public void addFeatureDrawModelsByClasses(Class ... classes) {
        for (Class c : classes) {
            AbstractGrapherModel model = grapherFactory.getDrawModelInstance(c);
            addFeatureDrawModels(model);
        }
    }

    public void removeFeatureDrawModel(AbstractGrapherModel ... models) {
        for (AbstractGrapherModel model : models) {
            featureDrawModels.remove(model);
        }
    }

    private void sortAbstractGrapherModels() {
        Collections.sort(getFeatureDrawModels(), new Comparator<AbstractGrapherModel>() {
            @Override
            public int compare(AbstractGrapherModel o1, AbstractGrapherModel o2) {
                int index1 = o1.getLayoutIndex();
                int index2 = o2.getLayoutIndex();
                if (index1 > index2) {
                    return 1;
                }else if (index1 < index2) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });
    }

    public void doPaint(Graphics g) {
        sortAbstractGrapherModels();
        for (AbstractGrapherModel model : getFeatureDrawModels()) {
            List<AbstractGrapherModel> dependenceModels = grapherFactory.getDependences(model);
            if (dependenceModels == null || dependenceModels.size() == 0) {
                model.draw(grapherFactory.getXFlowGraphicsInstance(g, grapherFactory.getTransformationByCustomizeRule(model)));
            }else{
                for (AbstractGrapherModel dependenceModel : dependenceModels) {
                    dependenceModel.draw(grapherFactory.getXFlowGraphicsInstance(g, grapherFactory.getTransformationByCustomizeRule(model)));
                }
            }
        }
    }

    public void removeFeatureDrawModelByClasses(Class ... classes) {
        for (Class c : classes) {
            AbstractGrapherModel model = grapherFactory.getDrawModelInstance(c);
            removeFeatureDrawModel(model);
        }
    }

    public String getModelParam(Class c, String key) {
        return getGrapherFactory().getDrawModelInstance(c).getParams().get(key);
    }

    public void setModelParam(Class c, String key, String value) {
        getGrapherFactory().getDrawModelInstance(c).getParams().put(key, value);
    }

    public void clearModelParam(Class c) {
        getGrapherFactory().getDrawModelInstance(c).getParams().clear();
    }

    public void addRegisterModels(Class c) {
        grapherFactory.registerGrapherModel(c);
    }

    public void setTransformationByClass(Class c) {
        grapherFactory.setTransformation(c);
    }
}
